This is an analysis of a dataset generated in the lab containing septum from E11.5 PGK-Cre;Rosa26YFP and E12.5 Dbx1-Cre;Rosa26Tomato embryos Cells were prepared by Matthieu Moreau & Frédéric Causeret
Libraries were generated by Matthieu Moreau & Frédéric Causeret
Sequencing was achieved at the genomics platform of Imagine
Reads were aligned on the mm10 genome to which were added: - YFP (“eYFP”)
- Tomato-WPRE-bGH (“dtTomato”)

1 Load libraries

library(Seurat)
library(dplyr)
library(patchwork)
library(cowplot)
library(ggplot2)
library(ggExtra)
library(Matrix)
library(RColorBrewer)
library(viridis)
library(wesanderson)
library(MetBrewer)


# Set ggplot theme as classic
theme_set(theme_classic())

2 Load the dataset and calculate QC metrics

2.1 Initialize a Seurat object from the raw filtered gene/bc matrix

# Load the raw filtered_gene_bc_matrix outputed by Cell Ranger
Countdata <- Read10X(data.dir = "/shared/ifbstor1/home/fcauseret/Septum/filtered_gene_bc_matrices/")

# Initialize the Seurat object
Septum <- CreateSeuratObject(counts = Countdata,
                               min.cells = 3,
                               min.features = 800,
                               project = "Septum")

Septum$Barcodes <- colnames(Septum)

dim(Septum)
## [1] 17280  5825
rm(Countdata)

2.2 Calculate percentage of mitochondrial and ribosomal counts

# Percent of mitochondrial counts
Septum[["percent.mt"]] <- PercentageFeatureSet(Septum, pattern = "^mt-")

# Percent of ribosomal counts
Septum[["percent.rb"]] <- PercentageFeatureSet(Septum, pattern = "(^Rpl|^Rps|^Mrp)")

2.3 Cell Quality according to the mitochondrial RNA percentage in the cells

# Filter cells based on these thresholds
Cell.QC.Stat <- Septum@meta.data
max.mito.thr <- median(Cell.QC.Stat$percent.mt) + 3*mad(Cell.QC.Stat$percent.mt)
min.mito.thr <- median(Cell.QC.Stat$percent.mt) - 3*mad(Cell.QC.Stat$percent.mt)
Cell.QC.Stat <- Cell.QC.Stat %>% filter(percent.mt < max.mito.thr) %>% filter(percent.mt > min.mito.thr)

Septum@meta.data$Cell.quality <- ifelse(Septum@meta.data$percent.mt > min.mito.thr & Septum@meta.data$percent.mt < max.mito.thr, "High Quality", "Low Quality")

table(Septum$Cell.quality)
## 
## High Quality  Low Quality 
##         5444          381
rm(Cell.QC.Stat, max.mito.thr, min.mito.thr)

2.4 Plot basic QC metrics

#Violin plot 
VlnPlot(Septum, features = c("nFeature_RNA", "nCount_RNA", "percent.mt", "percent.rb"), ncol = 4, group.by="Cell.quality")

2.4.1 Plot more QC metrics

# Relation between nCount_RNA and nFeatures_RNA detected with cell quality parameter
p1 <- ggplot(Septum@meta.data, aes(x=nCount_RNA, y=nFeature_RNA)) + geom_point(aes(color=Cell.quality), size=0.1) + geom_smooth(method="lm")
p1 <- ggMarginal(p1, type = "histogram", fill="lightgrey")

p2 <- ggplot(Septum@meta.data, aes(x=log10(nCount_RNA), y=log10(nFeature_RNA))) + geom_point(aes(color=Cell.quality), size=0.1) + geom_smooth(method="lm")
p2 <- ggMarginal(p2, type = "histogram", fill="lightgrey")

# Relation between nFeatures_RNA and the mitochondrial RNA percentage detected with cell quality parameter
p3 <- ggplot(Septum@meta.data, aes(x=nFeature_RNA, y=percent.mt, color=Cell.quality)) + geom_point(size=0.1)
p3 <- ggMarginal(p3, type = "histogram", fill="lightgrey", bins=100) 
    
plot_grid(plotlist = list(p1,p2,p3), ncol=3, align='h', rel_widths = c(1, 1, 1))

rm(p1, p2, p3)

2.5 Cell Cycle Scoring

# Assign cell-cycle scores
s.genes <- c("Mcm5", "Pcna", "Tym5", "Fen1", "Mcm2", "Mcm4", "Rrm1", "Ung", "Gins2", "Mcm6", "Cdca7", "Dtl", "Prim1", "Uhrf1", "Mlf1ip", "Hells", "Rfc2", "Rap2", "Nasp", "Rad51ap1", "Gmnn", "Wdr76", "Slbp", "Ccne2", "Ubr7", "Pold3", "Msh2", "Atad2", "Rad51", "Rrm2", "Cdc45", "Cdc6", "Exo1", "Tipin", "Dscc1", "Blm", " Casp8ap2", "Usp1", "Clspn", "Pola1", "Chaf1b", "Brip1", "E2f8")
g2m.genes <- c("Hmgb2", "Ddk1","Nusap1", "Ube2c", "Birc5", "Tpx2", "Top2a", "Ndc80", "Cks2", "Nuf2", "Cks1b", "Mki67", "Tmpo", " Cenpk", "Tacc3", "Fam64a", "Smc4", "Ccnb2", "Ckap2l", "Ckap2", "Aurkb", "Bub1", "Kif11", "Anp32e", "Tubb4b", "Gtse1", "kif20b", "Hjurp", "Cdca3", "Hn1", "Cdc20", "Ttk", "Cdc25c", "kif2c", "Rangap1", "Ncapd2", "Dlgap5", "Cdca2", "Cdca8", "Ect2", "Kif23", "Hmmr", "Aurka", "Psrc1", "Anln", "Lbr", "Ckap5", "Cenpe", "Ctcf", "Nek2", "G2e3", "Gas2l3", "Cbx5", "Cenpa")

Septum <- CellCycleScoring(Septum,
                             s.features = s.genes,
                             g2m.features = g2m.genes,
                             set.ident = T)
table(Septum$Phase)
## 
##   G1  G2M    S 
## 2691 1376 1758
rm(s.genes, g2m.genes)

3 Normalize counts

# LogNormalize the gene expression matrix (global-scaling normalization method)
Septum <- NormalizeData(Septum, normalization.method = "LogNormalize", scale.factor = 10000)

4 Identification of highly variable features (feature selection)

Septum <- FindVariableFeatures(Septum, selection.method = "vst", nfeatures = 2000)

# Identify the 10 most highly variable genes
top20 <- head(VariableFeatures(Septum), 20)

# Plot variable features with and without labels
plot1 <- VariableFeaturePlot(Septum) + theme(legend.position = "top")
plot2 <- LabelPoints(plot = plot1, points = top20, repel = T) + theme(legend.position = "none")
plot_grid(plotlist = list(plot1,plot2), ncol=2, align='h', rel_widths = c(1, 1))

rm(top20, plot1, plot2)

5 Scaling the data

# Linear transformation : Pre-processing step for dimensional reduction like PCA 
Septum <- ScaleData(Septum)

6 Perform linear dimensional reduction

Septum <- RunPCA(Septum, features = VariableFeatures(object = Septum))
# Examine and visualize PCA results a few different ways
print(Septum[["pca"]], dims = 1:5, nfeatures = 5)
## PC_ 1 
## Positive:  Mllt11, Tagln3, Rtn1, Tubb3, Tuba1a 
## Negative:  Hmgb2, Anp32b, Tuba1b, Dek, Phgdh 
## PC_ 2 
## Positive:  Alas2, Gypa, Car2, Acp5, Rhd 
## Negative:  Tubb2b, Pkm, Set, Map1b, Tuba1a 
## PC_ 3 
## Positive:  Fgf8, Fgf17, Serpinh1, Sparc, Zic4 
## Negative:  Alas2, Gypa, Pantr1, Car2, Efnb1 
## PC_ 4 
## Positive:  Arl6ip1, Cenpf, Ube2c, Nusap1, Prc1 
## Negative:  Ung, Pkm, Slc25a5, Mcm2, Mcm6 
## PC_ 5 
## Positive:  Cdkn1c, Hes6, Mfng, Dlk1, Rgs16 
## Negative:  Socs2, Gm3764, Wnt7b, Gas1, Thra
VizDimLoadings(Septum, dims = 1:2, reduction = "pca")

DimHeatmap(Septum, dims = 1:6, cells = 500, balanced = TRUE)

7 Determine the ‘dimensionality’ of the dataset

#  More approximate techniques such as those implemented in ElbowPlot() can be used to reduce computation time
Septum <- JackStraw(Septum, num.replicate = 100)
Septum <- ScoreJackStraw(Septum, dims = 1:20)

# JackStrawPlot
JackStrawPlot(Septum, dims = 1:20)

#ElbowPlot
ElbowPlot(Septum)

8 Run non-linear dimensional reduction (UMAP)

Septum <- RunUMAP(Septum, dims = 1:20)
DimPlot(Septum, reduction = "umap", label = TRUE, label.size = 3, pt.size = 0.1) + NoAxes()

9 Cluster the cells

Septum <- FindNeighbors(Septum, dims = 1:20)
Septum <- FindClusters(Septum, resolution = 1.5)
## Modularity Optimizer version 1.3.0 by Ludo Waltman and Nees Jan van Eck
## 
## Number of nodes: 5825
## Number of edges: 181940
## 
## Running Louvain algorithm...
## Maximum modularity in 10 random starts: 0.8266
## Number of communities: 24
## Elapsed time: 0 seconds
# Visualize clusters
DimPlot(Septum, reduction = "umap", label = TRUE, label.size = 3, pt.size = 0.1) + NoAxes() + ggtitle(paste(dim(Septum)[2], " septum cells")) 

10 Remove low quality, blood and meninges cells

DimPlot(Septum, reduction = "umap", label = TRUE, label.size = 3, pt.size = 0.1, group.by="Cell.quality") + NoAxes()

FeaturePlot(Septum, features = c("Hba-a1", "Col3a1"), order = T, 
            cols = c("grey90", brewer.pal(9,"YlOrRd"))) & NoLegend() & NoAxes()

Septum <- subset(Septum, idents = c(8, 20, 22), invert = TRUE)

DimPlot(Septum, reduction = "umap", label = TRUE, label.size = 3, pt.size = 0.1) + NoAxes() + ggtitle(paste(dim(Septum)[2], " cells after filtering")) 

11 Export files for Spring

11.1 Export raw expression matrix and gene list for spring plot generation

# Generate Spring dimensionality reduction
ExprsMatrix <- as.matrix(GetAssayData(Septum))
exprData <- Matrix(ExprsMatrix, sparse = TRUE)
writeMM(exprData, "ExprData.mtx")
## NULL
Genelist <- row.names(ExprsMatrix)
write.table(Genelist, "Genelist.csv", sep="\t", col.names = F, row.names = F)
rm(ExprsMatrix, exprData, Genelist)

11.2 Export continuous metadata

S.Score <- c("S.Score",Septum@meta.data$S.Score)
S.Score <- paste(S.Score, sep=",", collapse=",")

G2M.Score <- c("G2M.Score",Septum@meta.data$G2M.Score)
G2M.Score <- paste(G2M.Score, sep=",", collapse=",")

Percent.mt <- c("Percent.mt", Septum$percent.mt)
Percent.mt <- paste(Percent.mt, sep = ",", collapse = ",")

Percent.rb <- c("Percent.rb", Septum$percent.rb)
Percent.rb <- paste(Percent.rb, sep = ",", collapse = ",")

nCount <- c("nCount", Septum$nCount_RNA)
nCount <- paste(nCount, sep = ",", collapse = ",") 

nFeature <- c("nFeature", Septum$nFeature_RNA)
nFeature <- paste(nFeature, sep = ",", collapse = ",") 

ColorTrack <- rbind(S.Score, G2M.Score, Percent.mt, Percent.rb, nCount, nFeature)
write.table(ColorTrack, "ColorTrack.csv", quote =F, row.names = F, col.names = F)

rm(S.Score, G2M.Score, Percent.mt, Percent.rb, nCount, nFeature, ColorTrack)

11.3 Export discrete metadata

Seurat.clusters <- c("Seurat Clusters", paste0("Cluster",as.character(Septum@meta.data$seurat_clusters)))
Seurat.clusters <- paste(Seurat.clusters, sep=",", collapse=",")

Phase <- c("Phase", Septum@meta.data$Phase)
Phase <- paste(Phase, sep=",", collapse=",")

Quality <- c("Cell Quality", Septum$Cell.quality) 
Quality <- paste(Quality, sep = ",", collapse = ",") 

Cellgrouping <- rbind(Seurat.clusters, Phase, Quality)
write.table(Cellgrouping, "Cellgrouping.csv", quote =F, row.names = F, col.names = F)

rm(Cellgrouping, Seurat.clusters, Phase, Quality)

ExprData.mtx, Genelist.csv, ColorTrack.csv and Cellgrouping.csv are then used as input for the Spring App Cell coordinates of the Spring dimensionality reduction as well as doublet score are then downloaded

12 Import Spring doublet score (scrubblet) and remove doublets

doublet.score <- read.table("/shared/ifbstor1/home/fcauseret/Septum/doublet_results.tsv", header = T)
doublet.score <- filter(doublet.score, Observed_or_Simulated == "Observed")
rownames(doublet.score) <- Septum$Barcodes
Septum@meta.data$doublet.score <-doublet.score$Score
VlnPlot(object = Septum, features = "doublet.score", pt.size = 0.2) + geom_hline(yintercept = 0.4, linetype="dashed") + FeaturePlot(Septum, features = c("doublet.score"), order = T,
            cols = c("grey90", brewer.pal(9,"YlOrRd")))

Septum <- subset(Septum, subset = doublet.score < 0.4)

DimPlot(Septum, reduction = "umap", label = TRUE, label.size = 3, pt.size = 0.1) + NoAxes() + ggtitle(paste(dim(Septum)[2], " cells after doublets removal")) 

13 Import Spring coordinates

Coordinates <- read.table("/shared/ifbstor1/home/fcauseret/Septum/coordinates.txt", sep = ",", header = F)[,c(2,3)]
rownames(Coordinates) <- Septum$Barcodes
colnames(Coordinates) <- paste0("Spring_", 1:2)

# We will now store this as a custom dimensional reduction : spring
Septum[["Spring"]] <- CreateDimReducObject(embeddings = as.matrix(Coordinates), key = "Spring_", assay = DefaultAssay(Septum))

# Symmetry transform of the coordinates

Spring.Sym <- function(x){
  x = abs(max(Coordinates[,2])-x)
 }

Coordinates[,2] <- sapply(Coordinates[,2] , function(x) Spring.Sym(x))

Septum[["Spring"]] <- CreateDimReducObject(embeddings = as.matrix(Coordinates), key = "Spring_", assay = DefaultAssay(Septum))

rm(Coordinates, doublet.score)


# Spring visualization 
DimPlot(Septum, reduction = "Spring", pt.size = 0.2, label = T, label.size = 3) + NoAxes() + NoLegend()

FeaturePlot(Septum,
            features = c("Eomes", "Tbr1", "Isl1", "Trp73", "Onecut2", "Dbx1", "dtTomato", "Pcdh8", "Spon1"),
            reduction = "Spring",
            ncol = 3,
            order = T,
            cols = c("grey90", brewer.pal(9,"YlGnBu")))  & NoLegend() & NoAxes()

14 Distinguish E11 and E12 cells

YFP.Tom.df <- as.data.frame(t(Septum@assays[["RNA"]]@data))[,c("dtTomato", "eYFP")]
YFP.Tom.df$predicted.age <- as.factor(ifelse(YFP.Tom.df$dtTomato == 0 & YFP.Tom.df$eYFP > 0, 'E11',
                                             ifelse(YFP.Tom.df$dtTomato > 0 & YFP.Tom.df$eYFP > 0, 'Ambiguous', 'E12')))
table(YFP.Tom.df$predicted.age)
## 
## Ambiguous       E11       E12 
##       105      3572      1622
Septum@meta.data$predicted.age <- YFP.Tom.df$predicted.age

DimPlot(Septum, reduction = "Spring", pt.size = 0.2, label = T, label.size = 3, group.by = "predicted.age") + NoAxes() 

VlnPlot(subset(Septum, subset = predicted.age != "Ambiguous"),
        features = c("nCount_RNA", "nFeature_RNA"),
        split.by = "predicted.age",
        pt.size = 0,
        adjust = 1) + theme(legend.position = 'bottom')

FeaturePlot(Septum,
            features = c("dtTomato", "eYFP"),
            reduction = "Spring",
            split.by = "predicted.age",
            ncol = 3,
            order = T,
            cols = c("grey90", brewer.pal(9,"YlGnBu")))  & NoLegend() & NoAxes()

15 Save object

saveRDS(Septum, "/shared/ifbstor1/home/fcauseret/Septum/Septum.RDS")

16 Session Info

#date
format(Sys.time(), "%d %B, %Y, %H,%M")
## [1] "20 May, 2023, 13,10"
#Packages used
sessionInfo()
## R version 4.1.1 (2021-08-10)
## Platform: x86_64-conda-linux-gnu (64-bit)
## Running under: CentOS Linux 7 (Core)
## 
## Matrix products: default
## BLAS/LAPACK: /shared/ifbstor1/software/miniconda/envs/r-4.1.1/lib/libopenblasp-r0.3.18.so
## 
## locale:
##  [1] LC_CTYPE=en_US.UTF-8       LC_NUMERIC=C              
##  [3] LC_TIME=en_US.UTF-8        LC_COLLATE=en_US.UTF-8    
##  [5] LC_MONETARY=en_US.UTF-8    LC_MESSAGES=en_US.UTF-8   
##  [7] LC_PAPER=en_US.UTF-8       LC_NAME=C                 
##  [9] LC_ADDRESS=C               LC_TELEPHONE=C            
## [11] LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C       
## 
## attached base packages:
## [1] stats     graphics  grDevices utils     datasets  methods   base     
## 
## other attached packages:
##  [1] MetBrewer_0.2.0    wesanderson_0.3.6  viridis_0.6.2      viridisLite_0.4.1 
##  [5] RColorBrewer_1.1-3 Matrix_1.3-4       ggExtra_0.9        ggplot2_3.3.6     
##  [9] cowplot_1.1.1      patchwork_1.1.1    dplyr_1.0.10       sp_1.4-7          
## [13] SeuratObject_4.1.0 Seurat_4.1.1      
## 
## loaded via a namespace (and not attached):
##   [1] ggbeeswarm_0.6.0      Rtsne_0.16            colorspace_2.0-3     
##   [4] deldir_1.0-6          ellipsis_0.3.2        ggridges_0.5.3       
##   [7] rgdal_1.5-23          rstudioapi_0.13       spatstat.data_2.2-0  
##  [10] farver_2.1.1          leiden_0.3.10         listenv_0.8.0        
##  [13] ggrepel_0.9.1         RSpectra_0.16-1       fansi_1.0.3          
##  [16] codetools_0.2-18      splines_4.1.1         knitr_1.40           
##  [19] polyclip_1.10-0       jsonlite_1.8.2        ica_1.0-2            
##  [22] cluster_2.1.2         png_0.1-7             rgeos_0.5-9          
##  [25] uwot_0.1.11           shiny_1.7.1           sctransform_0.3.3    
##  [28] spatstat.sparse_2.1-1 compiler_4.1.1        httr_1.4.4           
##  [31] assertthat_0.2.1      fastmap_1.1.0         lazyeval_0.2.2       
##  [34] cli_3.4.1             later_1.3.0           htmltools_0.5.2      
##  [37] tools_4.1.1           igraph_1.3.1          gtable_0.3.1         
##  [40] glue_1.6.2            RANN_2.6.1            reshape2_1.4.4       
##  [43] Rcpp_1.0.9            scattermore_0.8       jquerylib_0.1.4      
##  [46] vctrs_0.4.2           nlme_3.1-153          progressr_0.10.0     
##  [49] lmtest_0.9-40         spatstat.random_2.2-0 xfun_0.34            
##  [52] stringr_1.4.1         globals_0.14.0        mime_0.12            
##  [55] miniUI_0.1.1.1        lifecycle_1.0.3       irlba_2.3.5.1        
##  [58] goftest_1.2-3         future_1.25.0         MASS_7.3-54          
##  [61] zoo_1.8-10            scales_1.2.1          spatstat.core_2.4-2  
##  [64] promises_1.2.0.1      spatstat.utils_2.3-0  parallel_4.1.1       
##  [67] yaml_2.3.6            reticulate_1.24       pbapply_1.5-0        
##  [70] gridExtra_2.3         ggrastr_1.0.1         sass_0.4.1           
##  [73] rpart_4.1-15          stringi_1.7.8         highr_0.9            
##  [76] rlang_1.0.6           pkgconfig_2.0.3       matrixStats_0.62.0   
##  [79] evaluate_0.17         lattice_0.20-45       tensor_1.5           
##  [82] ROCR_1.0-11           purrr_0.3.5           labeling_0.4.2       
##  [85] htmlwidgets_1.5.4     tidyselect_1.2.0      parallelly_1.31.1    
##  [88] RcppAnnoy_0.0.19      plyr_1.8.7            magrittr_2.0.3       
##  [91] R6_2.5.1              generics_0.1.3        DBI_1.1.2            
##  [94] withr_2.5.0           mgcv_1.8-38           pillar_1.8.1         
##  [97] fitdistrplus_1.1-8    survival_3.2-13       abind_1.4-5          
## [100] tibble_3.1.8          future.apply_1.9.0    crayon_1.5.2         
## [103] KernSmooth_2.23-20    utf8_1.2.2            spatstat.geom_2.4-0  
## [106] plotly_4.10.0         rmarkdown_2.11        grid_4.1.1           
## [109] data.table_1.14.2     digest_0.6.30         xtable_1.8-4         
## [112] tidyr_1.2.1           httpuv_1.6.5          munsell_0.5.0        
## [115] beeswarm_0.4.0        vipor_0.4.5           bslib_0.3.1

  1. IPNP & Imagine Institute, Paris, France, ↩︎

LS0tCnRpdGxlOiAiRTExLUUxMiBTZXB0dW0gZGF0YXNldCIKYXV0aG9yOiAKICAtIEZyw6lkw6lyaWMgQ2F1c2VyZXReW0lQTlAgJiBJbWFnaW5lIEluc3RpdHV0ZSwgUGFyaXMsIEZyYW5jZSwgZnJlZGVyaWMuY2F1c2VyZXRAaW5zZXJtLmZyXSBbIVtdKGh0dHBzOi8vb3JjaWQub3JnL3NpdGVzL2RlZmF1bHQvZmlsZXMvaW1hZ2VzL29yY2lkXzE2eDE2LnBuZyldKGh0dHBzOi8vb3JjaWQub3JnLzAwMDAtMDAwMi0wNTQzLTQ5MzgpCiAKZGF0ZTogImByIGZvcm1hdChTeXMudGltZSgpLCAnJWQgJUIsICVZJylgIgpvdXRwdXQ6CiAgaHRtbF9kb2N1bWVudDoKICAgIGNvZGVfZG93bmxvYWQ6IHllcwogICAgZGZfcHJpbnQ6IHBhZ2VkCiAgICBoaWdobGlnaHQ6IGhhZGRvY2sKICAgIHRoZW1lOiBjb3NtbwogICAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlCiAgICB0b2M6IHllcwogICAgdG9jX2RlcHRoOiA1CiAgICB0b2NfZmxvYXQ6CiAgICAgIGNvbGxhcHNlZDogeWVzCi0tLQoKYGBge2NzcywgZWNobz1GQUxTRX0KaDEgewogIGZvbnQtc2l6ZTogMzRweDsKICBtYXJnaW4tdG9wOiAycmVtOwogIG1hcmdpbi1ib3R0b206IDFyZW07CiAgY29sb3I6ICNlNjRkMDA7CiAgdGV4dC1kZWNvcmF0aW9uOiBub25lOwp9CmgxLnRpdGxlIHsKICBmb250LXNpemU6IDQwcHg7CiAgbWFyZ2luLXRvcDogMnJlbTsKICBtYXJnaW4tYm90dG9tOiAxcmVtOwogIHRleHQtYWxpZ246IGNlbnRlcjsKICB0ZXh0LWRlY29yYXRpb246IG5vbmU7CiAgY29sb3I6ICMwMDAwMDA7Cn0KaDIgewogIGZvbnQtc2l6ZTogMzBweDsKICBtYXJnaW4tdG9wOiAycmVtOwogIG1hcmdpbi1ib3R0b206IDFyZW07CiAgY29sb3I6ICMwMDAwMDA7Cn0KaDMgewogIGZvbnQtc2l6ZTogMjRweDsKICBtYXJnaW4tdG9wOiAycmVtOwogIG1hcmdpbi1ib3R0b206IDFyZW07CiAgY29sb3I6ICMwMDAwMDA7Cn0KaDQgewogIGZvbnQtc2l6ZTogMThweDsKICBtYXJnaW4tdG9wOiAycmVtOwogIG1hcmdpbi1ib3R0b206IDFyZW07CiAgY29sb3I6ICMwMDAwMDA7Cn0KaDUgewogIGZvbnQtc2l6ZTogMTZweDsKICBtYXJnaW4tdG9wOiAycmVtOwogIG1hcmdpbi1ib3R0b206IDFyZW07CiAgY29sb3I6ICMwMDAwMDA7Cn0KCnAgewogIGZvbnQtc2l6ZTogMTZweDsKfQpgYGAKCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUsIGZpZy5hbGlnbiA9ICdjZW50ZXInLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFKQpgYGAKCgpUaGlzIGlzIGFuIGFuYWx5c2lzIG9mIGEgZGF0YXNldCBnZW5lcmF0ZWQgaW4gdGhlIGxhYiBjb250YWluaW5nIHNlcHR1bSBmcm9tIEUxMS41IFBHSy1DcmU7Um9zYTI2WUZQIGFuZCBFMTIuNSBEYngxLUNyZTtSb3NhMjZUb21hdG8gZW1icnlvcwpDZWxscyB3ZXJlIHByZXBhcmVkIGJ5IE1hdHRoaWV1IE1vcmVhdSAmIEZyw6lkw6lyaWMgQ2F1c2VyZXQgIApMaWJyYXJpZXMgd2VyZSBnZW5lcmF0ZWQgYnkgTWF0dGhpZXUgTW9yZWF1ICYgRnLDqWTDqXJpYyBDYXVzZXJldCAgClNlcXVlbmNpbmcgd2FzIGFjaGlldmVkIGF0IHRoZSBnZW5vbWljcyBwbGF0Zm9ybSBvZiBJbWFnaW5lICAKUmVhZHMgd2VyZSBhbGlnbmVkIG9uIHRoZSBtbTEwIGdlbm9tZSB0byB3aGljaCB3ZXJlIGFkZGVkOiAKLSBZRlAgKCJlWUZQIikgIAotIFRvbWF0by1XUFJFLWJHSCAoImR0VG9tYXRvIikKCiMgTG9hZCBsaWJyYXJpZXMgIAoKYGBge3J9CmxpYnJhcnkoU2V1cmF0KQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KHBhdGNod29yaykKbGlicmFyeShjb3dwbG90KQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkoZ2dFeHRyYSkKbGlicmFyeShNYXRyaXgpCmxpYnJhcnkoUkNvbG9yQnJld2VyKQpsaWJyYXJ5KHZpcmlkaXMpCmxpYnJhcnkod2VzYW5kZXJzb24pCmxpYnJhcnkoTWV0QnJld2VyKQoKCiMgU2V0IGdncGxvdCB0aGVtZSBhcyBjbGFzc2ljCnRoZW1lX3NldCh0aGVtZV9jbGFzc2ljKCkpCmBgYAoKIyBMb2FkIHRoZSBkYXRhc2V0IGFuZCBjYWxjdWxhdGUgUUMgbWV0cmljcwoKIyMgSW5pdGlhbGl6ZSBhIFNldXJhdCBvYmplY3QgZnJvbSB0aGUgcmF3IGZpbHRlcmVkIGdlbmUvYmMgbWF0cml4CgpgYGB7ciBjYWNoZSA9IFRSVUV9CiMgTG9hZCB0aGUgcmF3IGZpbHRlcmVkX2dlbmVfYmNfbWF0cml4IG91dHB1dGVkIGJ5IENlbGwgUmFuZ2VyCkNvdW50ZGF0YSA8LSBSZWFkMTBYKGRhdGEuZGlyID0gIi9zaGFyZWQvaWZic3RvcjEvaG9tZS9mY2F1c2VyZXQvU2VwdHVtL2ZpbHRlcmVkX2dlbmVfYmNfbWF0cmljZXMvIikKCiMgSW5pdGlhbGl6ZSB0aGUgU2V1cmF0IG9iamVjdApTZXB0dW0gPC0gQ3JlYXRlU2V1cmF0T2JqZWN0KGNvdW50cyA9IENvdW50ZGF0YSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1pbi5jZWxscyA9IDMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtaW4uZmVhdHVyZXMgPSA4MDAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcm9qZWN0ID0gIlNlcHR1bSIpCgpTZXB0dW0kQmFyY29kZXMgPC0gY29sbmFtZXMoU2VwdHVtKQoKZGltKFNlcHR1bSkKCnJtKENvdW50ZGF0YSkKYGBgCgojIyBDYWxjdWxhdGUgcGVyY2VudGFnZSBvZiBtaXRvY2hvbmRyaWFsIGFuZCByaWJvc29tYWwgY291bnRzCgpgYGB7cn0KIyBQZXJjZW50IG9mIG1pdG9jaG9uZHJpYWwgY291bnRzClNlcHR1bVtbInBlcmNlbnQubXQiXV0gPC0gUGVyY2VudGFnZUZlYXR1cmVTZXQoU2VwdHVtLCBwYXR0ZXJuID0gIl5tdC0iKQoKIyBQZXJjZW50IG9mIHJpYm9zb21hbCBjb3VudHMKU2VwdHVtW1sicGVyY2VudC5yYiJdXSA8LSBQZXJjZW50YWdlRmVhdHVyZVNldChTZXB0dW0sIHBhdHRlcm4gPSAiKF5ScGx8XlJwc3xeTXJwKSIpCmBgYAoKIyMgQ2VsbCBRdWFsaXR5IGFjY29yZGluZyB0byB0aGUgbWl0b2Nob25kcmlhbCBSTkEgcGVyY2VudGFnZSBpbiB0aGUgY2VsbHMKCmBgYHtyfQojIEZpbHRlciBjZWxscyBiYXNlZCBvbiB0aGVzZSB0aHJlc2hvbGRzCkNlbGwuUUMuU3RhdCA8LSBTZXB0dW1AbWV0YS5kYXRhCm1heC5taXRvLnRociA8LSBtZWRpYW4oQ2VsbC5RQy5TdGF0JHBlcmNlbnQubXQpICsgMyptYWQoQ2VsbC5RQy5TdGF0JHBlcmNlbnQubXQpCm1pbi5taXRvLnRociA8LSBtZWRpYW4oQ2VsbC5RQy5TdGF0JHBlcmNlbnQubXQpIC0gMyptYWQoQ2VsbC5RQy5TdGF0JHBlcmNlbnQubXQpCkNlbGwuUUMuU3RhdCA8LSBDZWxsLlFDLlN0YXQgJT4lIGZpbHRlcihwZXJjZW50Lm10IDwgbWF4Lm1pdG8udGhyKSAlPiUgZmlsdGVyKHBlcmNlbnQubXQgPiBtaW4ubWl0by50aHIpCgpTZXB0dW1AbWV0YS5kYXRhJENlbGwucXVhbGl0eSA8LSBpZmVsc2UoU2VwdHVtQG1ldGEuZGF0YSRwZXJjZW50Lm10ID4gbWluLm1pdG8udGhyICYgU2VwdHVtQG1ldGEuZGF0YSRwZXJjZW50Lm10IDwgbWF4Lm1pdG8udGhyLCAiSGlnaCBRdWFsaXR5IiwgIkxvdyBRdWFsaXR5IikKCnRhYmxlKFNlcHR1bSRDZWxsLnF1YWxpdHkpCgpybShDZWxsLlFDLlN0YXQsIG1heC5taXRvLnRociwgbWluLm1pdG8udGhyKQpgYGAKCiMjIFBsb3QgYmFzaWMgUUMgbWV0cmljcwoKYGBge3IgZmlnLmRpbT1jKDIwLDEwKX0KI1Zpb2xpbiBwbG90IApWbG5QbG90KFNlcHR1bSwgZmVhdHVyZXMgPSBjKCJuRmVhdHVyZV9STkEiLCAibkNvdW50X1JOQSIsICJwZXJjZW50Lm10IiwgInBlcmNlbnQucmIiKSwgbmNvbCA9IDQsIGdyb3VwLmJ5PSJDZWxsLnF1YWxpdHkiKQpgYGAKCgojIyMgUGxvdCBtb3JlIFFDIG1ldHJpY3MKCmBgYHtyIGZpZy5kaW09YygyMCwgNyl9CiMgUmVsYXRpb24gYmV0d2VlbiBuQ291bnRfUk5BIGFuZCBuRmVhdHVyZXNfUk5BIGRldGVjdGVkIHdpdGggY2VsbCBxdWFsaXR5IHBhcmFtZXRlcgpwMSA8LSBnZ3Bsb3QoU2VwdHVtQG1ldGEuZGF0YSwgYWVzKHg9bkNvdW50X1JOQSwgeT1uRmVhdHVyZV9STkEpKSArIGdlb21fcG9pbnQoYWVzKGNvbG9yPUNlbGwucXVhbGl0eSksIHNpemU9MC4xKSArIGdlb21fc21vb3RoKG1ldGhvZD0ibG0iKQpwMSA8LSBnZ01hcmdpbmFsKHAxLCB0eXBlID0gImhpc3RvZ3JhbSIsIGZpbGw9ImxpZ2h0Z3JleSIpCgpwMiA8LSBnZ3Bsb3QoU2VwdHVtQG1ldGEuZGF0YSwgYWVzKHg9bG9nMTAobkNvdW50X1JOQSksIHk9bG9nMTAobkZlYXR1cmVfUk5BKSkpICsgZ2VvbV9wb2ludChhZXMoY29sb3I9Q2VsbC5xdWFsaXR5KSwgc2l6ZT0wLjEpICsgZ2VvbV9zbW9vdGgobWV0aG9kPSJsbSIpCnAyIDwtIGdnTWFyZ2luYWwocDIsIHR5cGUgPSAiaGlzdG9ncmFtIiwgZmlsbD0ibGlnaHRncmV5IikKCiMgUmVsYXRpb24gYmV0d2VlbiBuRmVhdHVyZXNfUk5BIGFuZCB0aGUgbWl0b2Nob25kcmlhbCBSTkEgcGVyY2VudGFnZSBkZXRlY3RlZCB3aXRoIGNlbGwgcXVhbGl0eSBwYXJhbWV0ZXIKcDMgPC0gZ2dwbG90KFNlcHR1bUBtZXRhLmRhdGEsIGFlcyh4PW5GZWF0dXJlX1JOQSwgeT1wZXJjZW50Lm10LCBjb2xvcj1DZWxsLnF1YWxpdHkpKSArIGdlb21fcG9pbnQoc2l6ZT0wLjEpCnAzIDwtIGdnTWFyZ2luYWwocDMsIHR5cGUgPSAiaGlzdG9ncmFtIiwgZmlsbD0ibGlnaHRncmV5IiwgYmlucz0xMDApIAogICAgCnBsb3RfZ3JpZChwbG90bGlzdCA9IGxpc3QocDEscDIscDMpLCBuY29sPTMsIGFsaWduPSdoJywgcmVsX3dpZHRocyA9IGMoMSwgMSwgMSkpCgpybShwMSwgcDIsIHAzKQpgYGAKCiMjIENlbGwgQ3ljbGUgU2NvcmluZwoKYGBge3J9CiMgQXNzaWduIGNlbGwtY3ljbGUgc2NvcmVzCnMuZ2VuZXMgPC0gYygiTWNtNSIsICJQY25hIiwgIlR5bTUiLCAiRmVuMSIsICJNY20yIiwgIk1jbTQiLCAiUnJtMSIsICJVbmciLCAiR2luczIiLCAiTWNtNiIsICJDZGNhNyIsICJEdGwiLCAiUHJpbTEiLCAiVWhyZjEiLCAiTWxmMWlwIiwgIkhlbGxzIiwgIlJmYzIiLCAiUmFwMiIsICJOYXNwIiwgIlJhZDUxYXAxIiwgIkdtbm4iLCAiV2RyNzYiLCAiU2xicCIsICJDY25lMiIsICJVYnI3IiwgIlBvbGQzIiwgIk1zaDIiLCAiQXRhZDIiLCAiUmFkNTEiLCAiUnJtMiIsICJDZGM0NSIsICJDZGM2IiwgIkV4bzEiLCAiVGlwaW4iLCAiRHNjYzEiLCAiQmxtIiwgIiBDYXNwOGFwMiIsICJVc3AxIiwgIkNsc3BuIiwgIlBvbGExIiwgIkNoYWYxYiIsICJCcmlwMSIsICJFMmY4IikKZzJtLmdlbmVzIDwtIGMoIkhtZ2IyIiwgIkRkazEiLCJOdXNhcDEiLCAiVWJlMmMiLCAiQmlyYzUiLCAiVHB4MiIsICJUb3AyYSIsICJOZGM4MCIsICJDa3MyIiwgIk51ZjIiLCAiQ2tzMWIiLCAiTWtpNjciLCAiVG1wbyIsICIgQ2VucGsiLCAiVGFjYzMiLCAiRmFtNjRhIiwgIlNtYzQiLCAiQ2NuYjIiLCAiQ2thcDJsIiwgIkNrYXAyIiwgIkF1cmtiIiwgIkJ1YjEiLCAiS2lmMTEiLCAiQW5wMzJlIiwgIlR1YmI0YiIsICJHdHNlMSIsICJraWYyMGIiLCAiSGp1cnAiLCAiQ2RjYTMiLCAiSG4xIiwgIkNkYzIwIiwgIlR0ayIsICJDZGMyNWMiLCAia2lmMmMiLCAiUmFuZ2FwMSIsICJOY2FwZDIiLCAiRGxnYXA1IiwgIkNkY2EyIiwgIkNkY2E4IiwgIkVjdDIiLCAiS2lmMjMiLCAiSG1tciIsICJBdXJrYSIsICJQc3JjMSIsICJBbmxuIiwgIkxiciIsICJDa2FwNSIsICJDZW5wZSIsICJDdGNmIiwgIk5lazIiLCAiRzJlMyIsICJHYXMybDMiLCAiQ2J4NSIsICJDZW5wYSIpCgpTZXB0dW0gPC0gQ2VsbEN5Y2xlU2NvcmluZyhTZXB0dW0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcy5mZWF0dXJlcyA9IHMuZ2VuZXMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZzJtLmZlYXR1cmVzID0gZzJtLmdlbmVzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNldC5pZGVudCA9IFQpCnRhYmxlKFNlcHR1bSRQaGFzZSkKcm0ocy5nZW5lcywgZzJtLmdlbmVzKQpgYGAKCgojIE5vcm1hbGl6ZSBjb3VudHMKCmBgYHtyfQojIExvZ05vcm1hbGl6ZSB0aGUgZ2VuZSBleHByZXNzaW9uIG1hdHJpeCAoZ2xvYmFsLXNjYWxpbmcgbm9ybWFsaXphdGlvbiBtZXRob2QpClNlcHR1bSA8LSBOb3JtYWxpemVEYXRhKFNlcHR1bSwgbm9ybWFsaXphdGlvbi5tZXRob2QgPSAiTG9nTm9ybWFsaXplIiwgc2NhbGUuZmFjdG9yID0gMTAwMDApCgpgYGAKCgojIElkZW50aWZpY2F0aW9uIG9mIGhpZ2hseSB2YXJpYWJsZSBmZWF0dXJlcyAoZmVhdHVyZSBzZWxlY3Rpb24pCgpgYGB7ciBmaWcuZGltPWMoMjAsIDEwKX0KU2VwdHVtIDwtIEZpbmRWYXJpYWJsZUZlYXR1cmVzKFNlcHR1bSwgc2VsZWN0aW9uLm1ldGhvZCA9ICJ2c3QiLCBuZmVhdHVyZXMgPSAyMDAwKQoKIyBJZGVudGlmeSB0aGUgMTAgbW9zdCBoaWdobHkgdmFyaWFibGUgZ2VuZXMKdG9wMjAgPC0gaGVhZChWYXJpYWJsZUZlYXR1cmVzKFNlcHR1bSksIDIwKQoKIyBQbG90IHZhcmlhYmxlIGZlYXR1cmVzIHdpdGggYW5kIHdpdGhvdXQgbGFiZWxzCnBsb3QxIDwtIFZhcmlhYmxlRmVhdHVyZVBsb3QoU2VwdHVtKSArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiKQpwbG90MiA8LSBMYWJlbFBvaW50cyhwbG90ID0gcGxvdDEsIHBvaW50cyA9IHRvcDIwLCByZXBlbCA9IFQpICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQpwbG90X2dyaWQocGxvdGxpc3QgPSBsaXN0KHBsb3QxLHBsb3QyKSwgbmNvbD0yLCBhbGlnbj0naCcsIHJlbF93aWR0aHMgPSBjKDEsIDEpKQoKCnJtKHRvcDIwLCBwbG90MSwgcGxvdDIpCmBgYAoKIyBTY2FsaW5nIHRoZSBkYXRhCgpgYGB7cn0KIyBMaW5lYXIgdHJhbnNmb3JtYXRpb24gOiBQcmUtcHJvY2Vzc2luZyBzdGVwIGZvciBkaW1lbnNpb25hbCByZWR1Y3Rpb24gbGlrZSBQQ0EgClNlcHR1bSA8LSBTY2FsZURhdGEoU2VwdHVtKQpgYGAKCiMgUGVyZm9ybSBsaW5lYXIgZGltZW5zaW9uYWwgcmVkdWN0aW9uCgpgYGB7cn0KU2VwdHVtIDwtIFJ1blBDQShTZXB0dW0sIGZlYXR1cmVzID0gVmFyaWFibGVGZWF0dXJlcyhvYmplY3QgPSBTZXB0dW0pKQojIEV4YW1pbmUgYW5kIHZpc3VhbGl6ZSBQQ0EgcmVzdWx0cyBhIGZldyBkaWZmZXJlbnQgd2F5cwpwcmludChTZXB0dW1bWyJwY2EiXV0sIGRpbXMgPSAxOjUsIG5mZWF0dXJlcyA9IDUpCgpWaXpEaW1Mb2FkaW5ncyhTZXB0dW0sIGRpbXMgPSAxOjIsIHJlZHVjdGlvbiA9ICJwY2EiKQoKRGltSGVhdG1hcChTZXB0dW0sIGRpbXMgPSAxOjYsIGNlbGxzID0gNTAwLCBiYWxhbmNlZCA9IFRSVUUpCgpgYGAKCiMgRGV0ZXJtaW5lIHRoZSAnZGltZW5zaW9uYWxpdHknIG9mIHRoZSBkYXRhc2V0CgpgYGB7ciBjYWNoZSA9IFRSVUV9CiMgIE1vcmUgYXBwcm94aW1hdGUgdGVjaG5pcXVlcyBzdWNoIGFzIHRob3NlIGltcGxlbWVudGVkIGluIEVsYm93UGxvdCgpIGNhbiBiZSB1c2VkIHRvIHJlZHVjZSBjb21wdXRhdGlvbiB0aW1lClNlcHR1bSA8LSBKYWNrU3RyYXcoU2VwdHVtLCBudW0ucmVwbGljYXRlID0gMTAwKQpTZXB0dW0gPC0gU2NvcmVKYWNrU3RyYXcoU2VwdHVtLCBkaW1zID0gMToyMCkKCiMgSmFja1N0cmF3UGxvdApKYWNrU3RyYXdQbG90KFNlcHR1bSwgZGltcyA9IDE6MjApCgojRWxib3dQbG90CkVsYm93UGxvdChTZXB0dW0pCmBgYAoKIyBSdW4gbm9uLWxpbmVhciBkaW1lbnNpb25hbCByZWR1Y3Rpb24gKFVNQVApCgpgYGB7ciBjYWNoZT1UUlVFfQpTZXB0dW0gPC0gUnVuVU1BUChTZXB0dW0sIGRpbXMgPSAxOjIwKQpEaW1QbG90KFNlcHR1bSwgcmVkdWN0aW9uID0gInVtYXAiLCBsYWJlbCA9IFRSVUUsIGxhYmVsLnNpemUgPSAzLCBwdC5zaXplID0gMC4xKSArIE5vQXhlcygpCmBgYAoKIyBDbHVzdGVyIHRoZSBjZWxscwoKYGBge3IgY2FjaGU9VFJVRX0KU2VwdHVtIDwtIEZpbmROZWlnaGJvcnMoU2VwdHVtLCBkaW1zID0gMToyMCkKU2VwdHVtIDwtIEZpbmRDbHVzdGVycyhTZXB0dW0sIHJlc29sdXRpb24gPSAxLjUpCgojIFZpc3VhbGl6ZSBjbHVzdGVycwpEaW1QbG90KFNlcHR1bSwgcmVkdWN0aW9uID0gInVtYXAiLCBsYWJlbCA9IFRSVUUsIGxhYmVsLnNpemUgPSAzLCBwdC5zaXplID0gMC4xKSArIE5vQXhlcygpICsgZ2d0aXRsZShwYXN0ZShkaW0oU2VwdHVtKVsyXSwgIiBzZXB0dW0gY2VsbHMiKSkgCgpgYGAKCiMgUmVtb3ZlIGxvdyBxdWFsaXR5LCBibG9vZCBhbmQgbWVuaW5nZXMgY2VsbHMKCmBgYHtyIGNhY2hlPVRSVUV9CkRpbVBsb3QoU2VwdHVtLCByZWR1Y3Rpb24gPSAidW1hcCIsIGxhYmVsID0gVFJVRSwgbGFiZWwuc2l6ZSA9IDMsIHB0LnNpemUgPSAwLjEsIGdyb3VwLmJ5PSJDZWxsLnF1YWxpdHkiKSArIE5vQXhlcygpCgpGZWF0dXJlUGxvdChTZXB0dW0sIGZlYXR1cmVzID0gYygiSGJhLWExIiwgIkNvbDNhMSIpLCBvcmRlciA9IFQsIAogICAgICAgICAgICBjb2xzID0gYygiZ3JleTkwIiwgYnJld2VyLnBhbCg5LCJZbE9yUmQiKSkpICYgTm9MZWdlbmQoKSAmIE5vQXhlcygpCgpTZXB0dW0gPC0gc3Vic2V0KFNlcHR1bSwgaWRlbnRzID0gYyg4LCAyMCwgMjIpLCBpbnZlcnQgPSBUUlVFKQoKRGltUGxvdChTZXB0dW0sIHJlZHVjdGlvbiA9ICJ1bWFwIiwgbGFiZWwgPSBUUlVFLCBsYWJlbC5zaXplID0gMywgcHQuc2l6ZSA9IDAuMSkgKyBOb0F4ZXMoKSArIGdndGl0bGUocGFzdGUoZGltKFNlcHR1bSlbMl0sICIgY2VsbHMgYWZ0ZXIgZmlsdGVyaW5nIikpIAoKYGBgCgojIEV4cG9ydCBmaWxlcyBmb3IgU3ByaW5nCgojIyBFeHBvcnQgcmF3IGV4cHJlc3Npb24gbWF0cml4IGFuZCBnZW5lIGxpc3QgZm9yIHNwcmluZyBwbG90IGdlbmVyYXRpb24KYGBge3IgY2FjaGUgPSBUUlVFfQojIEdlbmVyYXRlIFNwcmluZyBkaW1lbnNpb25hbGl0eSByZWR1Y3Rpb24KRXhwcnNNYXRyaXggPC0gYXMubWF0cml4KEdldEFzc2F5RGF0YShTZXB0dW0pKQpleHByRGF0YSA8LSBNYXRyaXgoRXhwcnNNYXRyaXgsIHNwYXJzZSA9IFRSVUUpCndyaXRlTU0oZXhwckRhdGEsICJFeHByRGF0YS5tdHgiKQoKR2VuZWxpc3QgPC0gcm93Lm5hbWVzKEV4cHJzTWF0cml4KQp3cml0ZS50YWJsZShHZW5lbGlzdCwgIkdlbmVsaXN0LmNzdiIsIHNlcD0iXHQiLCBjb2wubmFtZXMgPSBGLCByb3cubmFtZXMgPSBGKQpybShFeHByc01hdHJpeCwgZXhwckRhdGEsIEdlbmVsaXN0KQoKYGBgCgojIyBFeHBvcnQgY29udGludW91cyBtZXRhZGF0YQpgYGB7cn0KUy5TY29yZSA8LSBjKCJTLlNjb3JlIixTZXB0dW1AbWV0YS5kYXRhJFMuU2NvcmUpClMuU2NvcmUgPC0gcGFzdGUoUy5TY29yZSwgc2VwPSIsIiwgY29sbGFwc2U9IiwiKQoKRzJNLlNjb3JlIDwtIGMoIkcyTS5TY29yZSIsU2VwdHVtQG1ldGEuZGF0YSRHMk0uU2NvcmUpCkcyTS5TY29yZSA8LSBwYXN0ZShHMk0uU2NvcmUsIHNlcD0iLCIsIGNvbGxhcHNlPSIsIikKClBlcmNlbnQubXQgPC0gYygiUGVyY2VudC5tdCIsIFNlcHR1bSRwZXJjZW50Lm10KQpQZXJjZW50Lm10IDwtIHBhc3RlKFBlcmNlbnQubXQsIHNlcCA9ICIsIiwgY29sbGFwc2UgPSAiLCIpCgpQZXJjZW50LnJiIDwtIGMoIlBlcmNlbnQucmIiLCBTZXB0dW0kcGVyY2VudC5yYikKUGVyY2VudC5yYiA8LSBwYXN0ZShQZXJjZW50LnJiLCBzZXAgPSAiLCIsIGNvbGxhcHNlID0gIiwiKQoKbkNvdW50IDwtIGMoIm5Db3VudCIsIFNlcHR1bSRuQ291bnRfUk5BKQpuQ291bnQgPC0gcGFzdGUobkNvdW50LCBzZXAgPSAiLCIsIGNvbGxhcHNlID0gIiwiKSAKCm5GZWF0dXJlIDwtIGMoIm5GZWF0dXJlIiwgU2VwdHVtJG5GZWF0dXJlX1JOQSkKbkZlYXR1cmUgPC0gcGFzdGUobkZlYXR1cmUsIHNlcCA9ICIsIiwgY29sbGFwc2UgPSAiLCIpIAoKQ29sb3JUcmFjayA8LSByYmluZChTLlNjb3JlLCBHMk0uU2NvcmUsIFBlcmNlbnQubXQsIFBlcmNlbnQucmIsIG5Db3VudCwgbkZlYXR1cmUpCndyaXRlLnRhYmxlKENvbG9yVHJhY2ssICJDb2xvclRyYWNrLmNzdiIsIHF1b3RlID1GLCByb3cubmFtZXMgPSBGLCBjb2wubmFtZXMgPSBGKQoKcm0oUy5TY29yZSwgRzJNLlNjb3JlLCBQZXJjZW50Lm10LCBQZXJjZW50LnJiLCBuQ291bnQsIG5GZWF0dXJlLCBDb2xvclRyYWNrKQpgYGAKCiMjIEV4cG9ydCBkaXNjcmV0ZSBtZXRhZGF0YQpgYGB7cn0KClNldXJhdC5jbHVzdGVycyA8LSBjKCJTZXVyYXQgQ2x1c3RlcnMiLCBwYXN0ZTAoIkNsdXN0ZXIiLGFzLmNoYXJhY3RlcihTZXB0dW1AbWV0YS5kYXRhJHNldXJhdF9jbHVzdGVycykpKQpTZXVyYXQuY2x1c3RlcnMgPC0gcGFzdGUoU2V1cmF0LmNsdXN0ZXJzLCBzZXA9IiwiLCBjb2xsYXBzZT0iLCIpCgpQaGFzZSA8LSBjKCJQaGFzZSIsIFNlcHR1bUBtZXRhLmRhdGEkUGhhc2UpClBoYXNlIDwtIHBhc3RlKFBoYXNlLCBzZXA9IiwiLCBjb2xsYXBzZT0iLCIpCgpRdWFsaXR5IDwtIGMoIkNlbGwgUXVhbGl0eSIsIFNlcHR1bSRDZWxsLnF1YWxpdHkpIApRdWFsaXR5IDwtIHBhc3RlKFF1YWxpdHksIHNlcCA9ICIsIiwgY29sbGFwc2UgPSAiLCIpIAoKQ2VsbGdyb3VwaW5nIDwtIHJiaW5kKFNldXJhdC5jbHVzdGVycywgUGhhc2UsIFF1YWxpdHkpCndyaXRlLnRhYmxlKENlbGxncm91cGluZywgIkNlbGxncm91cGluZy5jc3YiLCBxdW90ZSA9Riwgcm93Lm5hbWVzID0gRiwgY29sLm5hbWVzID0gRikKCnJtKENlbGxncm91cGluZywgU2V1cmF0LmNsdXN0ZXJzLCBQaGFzZSwgUXVhbGl0eSkKYGBgCgpFeHByRGF0YS5tdHgsIEdlbmVsaXN0LmNzdiwgQ29sb3JUcmFjay5jc3YgYW5kIENlbGxncm91cGluZy5jc3YgYXJlIHRoZW4gdXNlZCBhcyBpbnB1dCBmb3IgdGhlIFNwcmluZyBBcHAKQ2VsbCBjb29yZGluYXRlcyBvZiB0aGUgU3ByaW5nIGRpbWVuc2lvbmFsaXR5IHJlZHVjdGlvbiBhcyB3ZWxsIGFzIGRvdWJsZXQgc2NvcmUgYXJlIHRoZW4gZG93bmxvYWRlZAoKIyBJbXBvcnQgU3ByaW5nIGRvdWJsZXQgc2NvcmUgKHNjcnViYmxldCkgYW5kIHJlbW92ZSBkb3VibGV0cwpgYGB7ciBmaWcuZGltPWMoNiwgNil9CmRvdWJsZXQuc2NvcmUgPC0gcmVhZC50YWJsZSgiL3NoYXJlZC9pZmJzdG9yMS9ob21lL2ZjYXVzZXJldC9TZXB0dW0vZG91YmxldF9yZXN1bHRzLnRzdiIsIGhlYWRlciA9IFQpCmRvdWJsZXQuc2NvcmUgPC0gZmlsdGVyKGRvdWJsZXQuc2NvcmUsIE9ic2VydmVkX29yX1NpbXVsYXRlZCA9PSAiT2JzZXJ2ZWQiKQpyb3duYW1lcyhkb3VibGV0LnNjb3JlKSA8LSBTZXB0dW0kQmFyY29kZXMKU2VwdHVtQG1ldGEuZGF0YSRkb3VibGV0LnNjb3JlIDwtZG91YmxldC5zY29yZSRTY29yZQpWbG5QbG90KG9iamVjdCA9IFNlcHR1bSwgZmVhdHVyZXMgPSAiZG91YmxldC5zY29yZSIsIHB0LnNpemUgPSAwLjIpICsgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMC40LCBsaW5ldHlwZT0iZGFzaGVkIikgKyBGZWF0dXJlUGxvdChTZXB0dW0sIGZlYXR1cmVzID0gYygiZG91YmxldC5zY29yZSIpLCBvcmRlciA9IFQsCiAgICAgICAgICAgIGNvbHMgPSBjKCJncmV5OTAiLCBicmV3ZXIucGFsKDksIllsT3JSZCIpKSkKCgpTZXB0dW0gPC0gc3Vic2V0KFNlcHR1bSwgc3Vic2V0ID0gZG91YmxldC5zY29yZSA8IDAuNCkKCkRpbVBsb3QoU2VwdHVtLCByZWR1Y3Rpb24gPSAidW1hcCIsIGxhYmVsID0gVFJVRSwgbGFiZWwuc2l6ZSA9IDMsIHB0LnNpemUgPSAwLjEpICsgTm9BeGVzKCkgKyBnZ3RpdGxlKHBhc3RlKGRpbShTZXB0dW0pWzJdLCAiIGNlbGxzIGFmdGVyIGRvdWJsZXRzIHJlbW92YWwiKSkgCgpgYGAKCgojIEltcG9ydCBTcHJpbmcgY29vcmRpbmF0ZXMKYGBge3IgZmlnLmRpbT1jKDYsIDYpfQpDb29yZGluYXRlcyA8LSByZWFkLnRhYmxlKCIvc2hhcmVkL2lmYnN0b3IxL2hvbWUvZmNhdXNlcmV0L1NlcHR1bS9jb29yZGluYXRlcy50eHQiLCBzZXAgPSAiLCIsIGhlYWRlciA9IEYpWyxjKDIsMyldCnJvd25hbWVzKENvb3JkaW5hdGVzKSA8LSBTZXB0dW0kQmFyY29kZXMKY29sbmFtZXMoQ29vcmRpbmF0ZXMpIDwtIHBhc3RlMCgiU3ByaW5nXyIsIDE6MikKCiMgV2Ugd2lsbCBub3cgc3RvcmUgdGhpcyBhcyBhIGN1c3RvbSBkaW1lbnNpb25hbCByZWR1Y3Rpb24gOiBzcHJpbmcKU2VwdHVtW1siU3ByaW5nIl1dIDwtIENyZWF0ZURpbVJlZHVjT2JqZWN0KGVtYmVkZGluZ3MgPSBhcy5tYXRyaXgoQ29vcmRpbmF0ZXMpLCBrZXkgPSAiU3ByaW5nXyIsIGFzc2F5ID0gRGVmYXVsdEFzc2F5KFNlcHR1bSkpCgojIFN5bW1ldHJ5IHRyYW5zZm9ybSBvZiB0aGUgY29vcmRpbmF0ZXMKClNwcmluZy5TeW0gPC0gZnVuY3Rpb24oeCl7CiAgeCA9IGFicyhtYXgoQ29vcmRpbmF0ZXNbLDJdKS14KQogfQoKQ29vcmRpbmF0ZXNbLDJdIDwtIHNhcHBseShDb29yZGluYXRlc1ssMl0gLCBmdW5jdGlvbih4KSBTcHJpbmcuU3ltKHgpKQoKU2VwdHVtW1siU3ByaW5nIl1dIDwtIENyZWF0ZURpbVJlZHVjT2JqZWN0KGVtYmVkZGluZ3MgPSBhcy5tYXRyaXgoQ29vcmRpbmF0ZXMpLCBrZXkgPSAiU3ByaW5nXyIsIGFzc2F5ID0gRGVmYXVsdEFzc2F5KFNlcHR1bSkpCgpybShDb29yZGluYXRlcywgZG91YmxldC5zY29yZSkKCgojIFNwcmluZyB2aXN1YWxpemF0aW9uIApEaW1QbG90KFNlcHR1bSwgcmVkdWN0aW9uID0gIlNwcmluZyIsIHB0LnNpemUgPSAwLjIsIGxhYmVsID0gVCwgbGFiZWwuc2l6ZSA9IDMpICsgTm9BeGVzKCkgKyBOb0xlZ2VuZCgpCgpGZWF0dXJlUGxvdChTZXB0dW0sCiAgICAgICAgICAgIGZlYXR1cmVzID0gYygiRW9tZXMiLCAiVGJyMSIsICJJc2wxIiwgIlRycDczIiwgIk9uZWN1dDIiLCAiRGJ4MSIsICJkdFRvbWF0byIsICJQY2RoOCIsICJTcG9uMSIpLAogICAgICAgICAgICByZWR1Y3Rpb24gPSAiU3ByaW5nIiwKICAgICAgICAgICAgbmNvbCA9IDMsCiAgICAgICAgICAgIG9yZGVyID0gVCwKICAgICAgICAgICAgY29scyA9IGMoImdyZXk5MCIsIGJyZXdlci5wYWwoOSwiWWxHbkJ1IikpKSAgJiBOb0xlZ2VuZCgpICYgTm9BeGVzKCkKCgoKYGBgCgojIERpc3Rpbmd1aXNoIEUxMSBhbmQgRTEyIGNlbGxzICAgCgpgYGB7cn0KWUZQLlRvbS5kZiA8LSBhcy5kYXRhLmZyYW1lKHQoU2VwdHVtQGFzc2F5c1tbIlJOQSJdXUBkYXRhKSlbLGMoImR0VG9tYXRvIiwgImVZRlAiKV0KWUZQLlRvbS5kZiRwcmVkaWN0ZWQuYWdlIDwtIGFzLmZhY3RvcihpZmVsc2UoWUZQLlRvbS5kZiRkdFRvbWF0byA9PSAwICYgWUZQLlRvbS5kZiRlWUZQID4gMCwgJ0UxMScsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShZRlAuVG9tLmRmJGR0VG9tYXRvID4gMCAmIFlGUC5Ub20uZGYkZVlGUCA+IDAsICdBbWJpZ3VvdXMnLCAnRTEyJykpKQp0YWJsZShZRlAuVG9tLmRmJHByZWRpY3RlZC5hZ2UpCgpTZXB0dW1AbWV0YS5kYXRhJHByZWRpY3RlZC5hZ2UgPC0gWUZQLlRvbS5kZiRwcmVkaWN0ZWQuYWdlCgpEaW1QbG90KFNlcHR1bSwgcmVkdWN0aW9uID0gIlNwcmluZyIsIHB0LnNpemUgPSAwLjIsIGxhYmVsID0gVCwgbGFiZWwuc2l6ZSA9IDMsIGdyb3VwLmJ5ID0gInByZWRpY3RlZC5hZ2UiKSArIE5vQXhlcygpIAoKVmxuUGxvdChzdWJzZXQoU2VwdHVtLCBzdWJzZXQgPSBwcmVkaWN0ZWQuYWdlICE9ICJBbWJpZ3VvdXMiKSwKICAgICAgICBmZWF0dXJlcyA9IGMoIm5Db3VudF9STkEiLCAibkZlYXR1cmVfUk5BIiksCiAgICAgICAgc3BsaXQuYnkgPSAicHJlZGljdGVkLmFnZSIsCiAgICAgICAgcHQuc2l6ZSA9IDAsCiAgICAgICAgYWRqdXN0ID0gMSkgKyB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAnYm90dG9tJykKCkZlYXR1cmVQbG90KFNlcHR1bSwKICAgICAgICAgICAgZmVhdHVyZXMgPSBjKCJkdFRvbWF0byIsICJlWUZQIiksCiAgICAgICAgICAgIHJlZHVjdGlvbiA9ICJTcHJpbmciLAogICAgICAgICAgICBzcGxpdC5ieSA9ICJwcmVkaWN0ZWQuYWdlIiwKICAgICAgICAgICAgbmNvbCA9IDMsCiAgICAgICAgICAgIG9yZGVyID0gVCwKICAgICAgICAgICAgY29scyA9IGMoImdyZXk5MCIsIGJyZXdlci5wYWwoOSwiWWxHbkJ1IikpKSAgJiBOb0xlZ2VuZCgpICYgTm9BeGVzKCkKCmBgYAoKIyBTYXZlIG9iamVjdCAgIAoKYGBge3J9CgpzYXZlUkRTKFNlcHR1bSwgIi9zaGFyZWQvaWZic3RvcjEvaG9tZS9mY2F1c2VyZXQvU2VwdHVtL1NlcHR1bS5SRFMiKQoKYGBgCgoKIyBTZXNzaW9uIEluZm8KCmBgYHtyfQojZGF0ZQpmb3JtYXQoU3lzLnRpbWUoKSwgIiVkICVCLCAlWSwgJUgsJU0iKQoKI1BhY2thZ2VzIHVzZWQKc2Vzc2lvbkluZm8oKQpgYGAKCgoKCgoKCgoKCgoKCg==